{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## LunarLanderContinuous-v2 (DDPG, v1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "threshold:  200\n",
      "Size of each action: 2\n",
      "Each observes a state with length: {} 8\n",
      "The state for the first agent looks like: -0.00059156417\n"
     ]
    }
   ],
   "source": [
    "import gym\n",
    "import random\n",
    "import torch\n",
    "import numpy as np\n",
    "\n",
    "import time\n",
    "#from ddpg_agent import Agent, ReplayBuffer, device\n",
    "from ddpg_agent_1 import Agent, ReplayBuffer, device\n",
    "from collections import deque\n",
    "\n",
    "start_timestep=1e4\n",
    "\n",
    "from  collections  import deque\n",
    "\n",
    "env = gym.make('LunarLanderContinuous-v2')\n",
    "seed = 0\n",
    "env.seed(seed)\n",
    "torch.manual_seed(seed)\n",
    "np.random.seed(seed)\n",
    "\n",
    "state = env.reset()\n",
    "state_dim = env.observation_space.shape[0]\n",
    "action_dim = env.action_space.shape[0] \n",
    "max_action = float(env.action_space.high[0])\n",
    "threshold = env.spec.reward_threshold\n",
    "print('threshold: ', threshold)\n",
    "\n",
    "print('Size of each action:', action_dim)\n",
    "# examine the state space \n",
    "print('Each observes a state with length: {}', state_dim)\n",
    "print('The state for the first agent looks like:', state[0])\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "agent = Agent(state_size=state_dim, action_size=action_dim, random_seed=8)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 10 Score: -312.26 Average Score: -508.87, Time: 00:00:04 ***    \n",
      "Episode 20 Score: -231.30 Average Score: -601.98, Time: 00:00:15 ***    \n",
      "Episode 30 Score: -329.78 Average Score: -512.62, Time: 00:00:22 ***    \n",
      "Episode 40 Score: -337.07 Average Score: -468.51, Time: 00:00:27 ***    \n",
      "Episode 50 Score: -349.80 Average Score: -442.29, Time: 00:00:32 ***    \n",
      "Episode 60 Score: -368.60 Average Score: -426.55, Time: 00:00:37 ***    \n",
      "Episode 70 Score: -278.15 Average Score: -402.61, Time: 00:00:44 ***    \n",
      "Episode 80 Score: -74.54 Average Score: -382.30, Time: 00:00:50 ***    \n",
      "Episode 90 Score: -226.69 Average Score: -362.21, Time: 00:00:58 ***    \n",
      "Episode 100 Score: 6.01 Average Score: -351.43, Time: 00:01:07 ***    \n",
      "Episode 110 Score: -7.86 Average Score: -330.51, Time: 00:01:19 ***    \n",
      "Episode 120 Score: -443.82 Average Score: -289.74, Time: 00:01:34 ***    \n",
      "Episode 130 Score: -319.18 Average Score: -301.73, Time: 00:01:51 ***    \n",
      "Episode 140 Score: -303.96 Average Score: -305.58, Time: 00:02:33 ***    \n",
      "Episode 150 Score: -97.44 Average Score: -285.72, Time: 00:03:54 ***    \n",
      "Episode 160 Score: -117.09 Average Score: -264.83, Time: 00:05:38 ***    \n",
      "Episode 170 Score: -354.35 Average Score: -266.59, Time: 00:06:27 ***    \n",
      "Episode 180 Score: -97.24 Average Score: -260.78, Time: 00:07:22 ***    \n",
      "Episode 190 Score: -85.98 Average Score: -255.85, Time: 00:08:50 ***    \n",
      "Episode 200 Score: -147.45 Average Score: -244.19, Time: 00:10:30 ***    \n",
      "Episode 210 Score: -81.34 Average Score: -228.08, Time: 00:11:55 ***    \n",
      "Episode 220 Score: -104.57 Average Score: -214.54, Time: 00:13:14 ***    \n",
      "Episode 230 Score: -150.55 Average Score: -185.53, Time: 00:14:24 ***    \n",
      "Episode 240 Score: -127.88 Average Score: -163.92, Time: 00:15:10 ***    \n",
      "Episode 250 Score: -127.98 Average Score: -164.80, Time: 00:15:48 ***    \n",
      "Episode 260 Score: -230.65 Average Score: -169.41, Time: 00:16:40 ***    \n",
      "Episode 270 Score: -223.00 Average Score: -158.43, Time: 00:18:03 ***    \n",
      "Episode 280 Score: -51.84 Average Score: -149.45, Time: 00:19:46 ***    \n",
      "Episode 290 Score: -0.65 Average Score: -142.04, Time: 00:21:20 ***    \n",
      "Episode 300 Score: -62.32 Average Score: -133.00, Time: 00:23:07 ***    \n",
      "Episode 310 Score: -201.72 Average Score: -125.69, Time: 00:24:40 ***    \n",
      "Episode 320 Score: 146.30 Average Score: -112.32, Time: 00:25:54 ***    \n",
      "Episode 330 Score: 93.91 Average Score: -95.50, Time: 00:26:57 ***    \n",
      "Episode 340 Score: -74.23 Average Score: -83.56, Time: 00:28:18 ***    \n",
      "Episode 350 Score: -174.14 Average Score: -76.51, Time: 00:29:28 ***    \n",
      "Episode 360 Score: 96.79 Average Score: -58.72, Time: 00:30:47 ***    \n",
      "Episode 370 Score: -181.15 Average Score: -48.83, Time: 00:32:14 ***    \n",
      "Episode 380 Score: -76.46 Average Score: -45.70, Time: 00:33:44 ***    \n",
      "Episode 390 Score: -106.22 Average Score: -45.04, Time: 00:35:38 ***    \n",
      "Episode 400 Score: -78.96 Average Score: -47.57, Time: 00:37:28 ***    \n",
      "Episode 410 Score: -4.06 Average Score: -42.25, Time: 00:39:16 ***    \n",
      "Episode 420 Score: -38.96 Average Score: -43.03, Time: 00:41:01 ***    \n",
      "Episode 430 Score: -74.10 Average Score: -50.56, Time: 00:42:39 ***    \n",
      "Episode 440 Score: -185.74 Average Score: -56.40, Time: 00:44:11 ***    \n",
      "Episode 450 Score: -66.01 Average Score: -56.82, Time: 00:45:45 ***    \n",
      "Episode 460 Score: -62.71 Average Score: -63.31, Time: 00:47:19 ***    \n",
      "Episode 470 Score: -38.93 Average Score: -61.19, Time: 00:49:05 ***    \n",
      "Episode 480 Score: -107.61 Average Score: -62.94, Time: 00:50:46 ***    \n",
      "Episode 490 Score: -75.93 Average Score: -65.00, Time: 00:52:23 ***    \n",
      "Episode 500 Score: -136.79 Average Score: -67.67, Time: 00:54:00 ***    \n",
      "Episode 510 Score: -42.74 Average Score: -75.37, Time: 00:55:39 ***    \n",
      "Episode 520 Score: -20.05 Average Score: -76.82, Time: 00:57:12 ***    \n",
      "Episode 530 Score: -19.68 Average Score: -71.73, Time: 00:58:50 ***    \n",
      "Episode 540 Score: -29.58 Average Score: -62.78, Time: 01:00:31 ***    \n",
      "Episode 550 Score: 172.62 Average Score: -54.87, Time: 01:02:09 ***    \n",
      "Episode 560 Score: 101.32 Average Score: -50.07, Time: 01:03:29 ***    \n",
      "Episode 570 Score: -23.83 Average Score: -49.73, Time: 01:04:57 ***    \n",
      "Episode 580 Score: -16.09 Average Score: -45.74, Time: 01:06:48 ***    \n",
      "Episode 590 Score: 140.18 Average Score: -32.83, Time: 01:08:38 ***    \n",
      "Episode 600 Score: 115.93 Average Score: -16.60, Time: 01:10:24 ***    \n",
      "Episode 610 Score: 230.58 Average Score: 12.55, Time: 01:11:34 ***    \n",
      "Episode 620 Score: 129.24 Average Score: 33.46, Time: 01:12:53 ***    \n",
      "Episode 630 Score: 91.91 Average Score: 49.49, Time: 01:14:19 ***    \n",
      "Episode 640 Score: 58.73 Average Score: 65.15, Time: 01:15:38 ***    \n",
      "Episode 650 Score: 176.09 Average Score: 77.29, Time: 01:17:04 ***    \n",
      "Episode 660 Score: 240.15 Average Score: 93.67, Time: 01:18:21 ***    \n",
      "Episode 670 Score: 185.35 Average Score: 119.54, Time: 01:19:19 ***    \n",
      "Episode 680 Score: 210.95 Average Score: 143.62, Time: 01:20:15 ***    \n",
      "Episode 690 Score: 218.96 Average Score: 160.28, Time: 01:21:15 ***    \n",
      "Episode 700 Score: 280.84 Average Score: 175.06, Time: 01:22:27 ***    \n",
      "Episode 710 Score: 266.14 Average Score: 178.35, Time: 01:23:32 ***    \n",
      "Episode 720 Score: 232.64 Average Score: 181.89, Time: 01:24:34 ***    \n",
      "Episode 730 Score: 169.02 Average Score: 189.02, Time: 01:25:34 ***    \n",
      "Episode 740 Score: 191.62 Average Score: 194.17, Time: 01:26:18 ***    \n",
      "Episode 746 Score: 139.54 Average Score: 200.03, Time: 01:26:49 ***    \n",
      "Environment solved !   \n"
     ]
    }
   ],
   "source": [
    "def ddpg(n_episodes=20000, print_every=10):\n",
    "    scores_deque = deque(maxlen=100)\n",
    "    scores_array = []\n",
    "    avg_scores_array = [] \n",
    "        \n",
    "    time_start = time.time()\n",
    "    \n",
    "    timestep_after_last_save = 0\n",
    "    total_timesteps = 0\n",
    "        \n",
    "    for i_episode in range(1, n_episodes+1):\n",
    "        state = env.reset()                                    # set the environment    \n",
    "        agent.reset()\n",
    "        score_average = 0\n",
    "        \n",
    "        timestep = 0\n",
    "        total_reward = 0\n",
    "        \n",
    "        done = False\n",
    "\n",
    "        while True:\n",
    "            action = agent.act(state)\n",
    "                        \n",
    "            # Perform action\n",
    "            next_state, reward, done, _ = env.step(action) \n",
    "            done_bool = 0 if timestep + 1 == env._max_episode_steps else float(done)\n",
    "            total_reward += reward                          # full episode reward\n",
    "        \n",
    "            ## def step(self, states, actions, rewards, next_states, dones, timestep):\n",
    "            agent.step(state, action, reward, next_state, done, timestep)\n",
    "            state = next_state                               # roll over states to next time step\n",
    "            \n",
    "            timestep += 1     \n",
    "            total_timesteps += 1\n",
    "            timestep_after_last_save += 1\n",
    "\n",
    "            if done:                                  # exit loop if episode finished\n",
    "                break\n",
    "        \n",
    "        scores_deque.append(total_reward)\n",
    "        scores_array.append(total_reward)\n",
    "\n",
    "        avg_score = np.mean(scores_deque)\n",
    "        avg_scores_array.append(avg_score)\n",
    "        \n",
    "        # train_by_episode(time_start, i_episode) \n",
    "        s = (int)(time.time() - time_start)\n",
    "                        \n",
    "        if i_episode % print_every == 0 or (len(scores_deque) == 100 and np.mean(scores_deque) >= threshold) :\n",
    "            #torch.save(agent.actor_local.state_dict(), 'checkpoint_actor.pth')\n",
    "            #torch.save(agent.critic_local.state_dict(), 'checkpoint_critic.pth')\n",
    "            s = (int)(time.time() - time_start) \n",
    "            print('Episode {} Score: {:.2f} Average Score: {:.2f}, Time: {:02}:{:02}:{:02} ***    '\\\n",
    "                  .format(i_episode, total_reward, avg_score, s//3600, s%3600//60, s%60))  \n",
    "            \n",
    "        if len(scores_deque) == 100 and np.mean(scores_deque) >= threshold:  \n",
    "            print('Environment solved !   ')\n",
    "            break\n",
    "            \n",
    "    return scores_array, avg_scores_array\n",
    "\n",
    "scores, avg_scores = ddpg()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "ax = fig.add_subplot(111)\n",
    "plt.plot(np.arange(1, len(scores)+1), scores, label=\"Score\")\n",
    "plt.plot(np.arange(1, len(avg_scores)+1), avg_scores, label=\"Avg on 100 episodes\")\n",
    "plt.legend(bbox_to_anchor=(1.05, 1)) \n",
    "plt.ylabel('Score')\n",
    "plt.xlabel('Episodes #')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def save(agent, filename, directory):\n",
    "    torch.save(agent.actor_local.state_dict(), '%s/%s_actor_local.pth' % (directory, filename))\n",
    "    torch.save(agent.actor_target.state_dict(), '%s/%s_actor_target.pth' % (directory, filename))\n",
    "    torch.save(agent.critic_local.state_dict(), '%s/%s_critic_local.pth' % (directory, filename))\n",
    "    torch.save(agent.critic_target.state_dict(), '%s/%s_critic_target.pth' % (directory, filename))\n",
    "\n",
    "\n",
    "save(agent, 'LunarLanderContinuous-v2', 'dir_chk_test')\n",
    "\n",
    "model.save_state_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def play(env, agent, n_episodes):\n",
    "    \n",
    "    state = env.reset()\n",
    "    scores_deque = deque(maxlen=100)\n",
    "\n",
    "    for i_episode in range(1, n_episodes+1):\n",
    "        state = env.reset()\n",
    "        agent.reset()\n",
    "        \n",
    "        total_reward = 0\n",
    "        time_start = time.time()\n",
    "        timesteps =  0\n",
    "        \n",
    "        done = False\n",
    "\n",
    "        while True:\n",
    "            \n",
    "            action = agent.act(state)\n",
    "            env.render()\n",
    "            next_state, reward, done, _ = env.step(action)\n",
    "            total_reward += reward\n",
    "            \n",
    "            agent.step(state, action, reward, next_state, done, timesteps)\n",
    "            state = next_state\n",
    "            timesteps += 1\n",
    "            \n",
    "            if done:\n",
    "                break \n",
    "\n",
    "        delta = (int)(time.time() - time_start)\n",
    "        \n",
    "        scores_deque.append(total_reward)\n",
    "\n",
    "        print('Episode {}\\tAverage Score: {:.2f}, \\t Timesteps: {} \\tTime: {:02}:{:02}:{:02}'\\\n",
    "                  .format(i_episode, np.mean(scores_deque), timesteps,\\\n",
    "                          delta//3600, delta%3600//60, delta%60))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 1\tAverage Score: 170.48, \t Timesteps: 548 \tTime: 00:00:14\n",
      "Episode 2\tAverage Score: 190.28, \t Timesteps: 530 \tTime: 00:00:13\n",
      "Episode 3\tAverage Score: 186.39, \t Timesteps: 447 \tTime: 00:00:11\n",
      "Episode 4\tAverage Score: 193.44, \t Timesteps: 493 \tTime: 00:00:12\n",
      "Episode 5\tAverage Score: 198.37, \t Timesteps: 571 \tTime: 00:00:14\n",
      "Episode 6\tAverage Score: 199.58, \t Timesteps: 569 \tTime: 00:00:14\n",
      "Episode 7\tAverage Score: 198.41, \t Timesteps: 831 \tTime: 00:00:20\n",
      "Episode 8\tAverage Score: 194.49, \t Timesteps: 574 \tTime: 00:00:14\n",
      "Episode 9\tAverage Score: 191.80, \t Timesteps: 395 \tTime: 00:00:09\n",
      "Episode 10\tAverage Score: 195.02, \t Timesteps: 386 \tTime: 00:00:09\n"
     ]
    }
   ],
   "source": [
    "play(env=env, agent=agent, n_episodes=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "save(agent, 'LLC-v2', 'dir_chk_1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load(agent, directory, filename):\n",
    "    agent.actor_local.load_state_dict(torch.load('%s/%s_actor_local.pth' % (directory,  filename)))\n",
    "    agent.actor_target.load_state_dict(torch.load('%s/%s_actor_target.pth' % (directory,  filename)))\n",
    "    agent.critic_local.load_state_dict(torch.load('%s/%s_critic_local.pth' % (directory,  filename)))\n",
    "    agent.critic_target.load_state_dict(torch.load('%s/%s_critic_target.pth' % (directory,  filename)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Episode 1\tAverage Score: 255.19, \t Timesteps: 346 \tTime: 00:00:17\n",
      "Episode 2\tAverage Score: 253.04, \t Timesteps: 339 \tTime: 00:00:08\n",
      "Episode 3\tAverage Score: 254.17, \t Timesteps: 414 \tTime: 00:00:11\n",
      "Episode 4\tAverage Score: 254.71, \t Timesteps: 379 \tTime: 00:00:09\n",
      "Episode 5\tAverage Score: 254.58, \t Timesteps: 368 \tTime: 00:00:09\n",
      "Episode 6\tAverage Score: 252.35, \t Timesteps: 464 \tTime: 00:00:11\n",
      "Episode 7\tAverage Score: 248.49, \t Timesteps: 328 \tTime: 00:00:08\n"
     ]
    }
   ],
   "source": [
    "load(agent, 'dir_chk_1', 'LLC-v2')\n",
    "play(env=env, agent=agent, n_episodes=7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "env.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ml2-kernel",
   "language": "python",
   "name": "ml2-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
